package com.wenx.v3system.modular.cloud.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wenx.v3core.error.BusinessException;
import com.wenx.v3system.modular.cloud.domain.dto.SysDepartmentDto;
import com.wenx.v3system.modular.cloud.domain.dto.SysUserDto;
import com.wenx.v3system.modular.cloud.domain.maps.SysDepartmentMap;
import com.wenx.v3system.modular.cloud.domain.maps.SysUserMap;
import com.wenx.v3system.modular.cloud.domain.po.SysDepartment;
import com.wenx.v3system.modular.cloud.domain.po.SysDepartmentUser;
import com.wenx.v3system.modular.cloud.domain.po.SysRole;
import com.wenx.v3system.modular.cloud.domain.po.SysUser;
import com.wenx.v3system.modular.cloud.domain.po.SysUserRole;
import com.wenx.v3system.modular.cloud.domain.dto.DepartmentOperateDto;
import com.wenx.v3system.modular.cloud.domain.query.DepartmentQuery;
import com.wenx.v3system.modular.cloud.domain.query.SysDepartmentQuery;
import com.wenx.v3system.modular.cloud.mapper.SysDepartmentMapper;
import com.wenx.v3system.modular.cloud.mapper.SysDepartmentUserMapper;
import com.wenx.v3system.modular.cloud.mapper.SysRoleMapper;
import com.wenx.v3system.modular.cloud.mapper.SysUserMapper;
import com.wenx.v3system.modular.cloud.mapper.SysUserRoleMapper;
import com.wenx.v3system.modular.cloud.service.SysDepartmentRestService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

import static com.wenx.v3secure.enums.SystemRoleType.DEPT_ADMIN;

/**
 * 系统部门服务实现类
 * 基于Enhanced RBAC权限模型
 * 提供部门管理、组织架构和层级关系操作
 * 
 * @author wenx
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysDepartmentRestServiceImpl extends ServiceImpl<SysDepartmentMapper, SysDepartment> implements SysDepartmentRestService {

    private final SysDepartmentMap departmentMap;
    private final SysDepartmentUserMapper departmentUserMapper;
    private final SysUserMapper userMapper;
    private final SysRoleMapper sysRoleMapper;
    private final SysUserRoleMapper sysUserRoleMapper;

    // 缓存常量
    private static final String DEPARTMENT_CACHE = "sys:department";
    private static final String DEPARTMENT_TREE_CACHE = "sys:department:tree";
    private static final String USER_DEPARTMENT_CACHE = "sys:user:department";
    private static final String DEPARTMENT_USERS_CACHE = "sys:department:users";

    @Override
    public IPage<?> page(SysDepartmentQuery query) {
        log.debug("分页查询部门，查询条件: {}", query);
        
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<SysDepartment>()
                .like(StringUtils.hasText(query.getName()), SysDepartment::getName, query.getName())
                .like(StringUtils.hasText(query.getCode()), SysDepartment::getCode, query.getCode())
                .eq(query.getParentId() != null, SysDepartment::getParentId, query.getParentId())
                .eq(query.getStatus() != null, SysDepartment::getStatus, query.getStatus())
                .eq(SysDepartment::getDeleted, false)
                .orderByAsc(SysDepartment::getSort)
                .orderByDesc(SysDepartment::getCreateTime);
        
        Page<SysDepartment> page = new Page<>(query.getCurrent(), query.getSize());
        IPage<SysDepartment> departmentPage = super.page(page, wrapper);
        
        return departmentPage.convert(SysDepartmentMap.INSTANCE::toDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {DEPARTMENT_CACHE, DEPARTMENT_TREE_CACHE}, allEntries = true)
    public void add(SysDepartmentDto dto) {
        validateDepartmentDto(dto);
        
        if (existsByCode(dto.getCode(), null)) {
            throw new BusinessException("部门编码已存在: " + dto.getCode());
        }
        
        SysDepartment department = departmentMap.toPo(dto);
        setDefaultValues(department);
        buildAncestors(department);
        
        if (!super.save(department)) {
            throw new BusinessException("部门新增失败");
        }
        
        log.info("新增部门成功，部门ID: {}, 部门名称: {}", department.getId(), department.getName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {DEPARTMENT_CACHE, DEPARTMENT_TREE_CACHE, USER_DEPARTMENT_CACHE, DEPARTMENT_USERS_CACHE}, allEntries = true)
    public void delete(Serializable id) {
        SysDepartment department = getByIdOrThrow(id);
        
        if (!getChildDepartments((Long) id).isEmpty()) {
            throw new BusinessException("存在子部门，无法删除");
        }
        
        if (!getDepartmentUsers((Long) id, false).isEmpty()) {
            throw new BusinessException("部门下存在用户，无法删除");
        }
        
        if (!super.removeById(id)) {
            throw new BusinessException("部门删除失败");
        }
        
        log.info("删除部门成功，部门ID: {}", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {DEPARTMENT_CACHE, DEPARTMENT_TREE_CACHE}, allEntries = true)
    public void update(SysDepartmentDto dto) {
        if (dto.getId() == null) {
            throw new BusinessException("部门ID不能为空");
        }
        
        SysDepartment existingDepartment = getByIdOrThrow(dto.getId());
        
        if (existsByCode(dto.getCode(), dto.getId())) {
            throw new BusinessException("部门编码已存在: " + dto.getCode());
        }
        
        SysDepartment department = departmentMap.toPo(dto);
        department.setId(existingDepartment.getId());
        department.setCreateTime(existingDepartment.getCreateTime());
        department.setCreateBy(existingDepartment.getCreateBy());
        
        if (!super.updateById(department)) {
            throw new BusinessException("部门更新失败");
        }
        
        log.info("更新部门成功，部门ID: {}", dto.getId());
    }

    @Override
    @Cacheable(value = DEPARTMENT_CACHE, key = "#id")
    public SysDepartmentDto get(Serializable id) {
        SysDepartment department = super.getById(id);
        return department != null ? departmentMap.toDto(department) : null;
    }

    @Override
    @Cacheable(value = DEPARTMENT_CACHE, key = "'code:' + #code")
    public SysDepartmentDto getDepartmentByCode(String code) {
        if (!StringUtils.hasText(code)) {
            throw new BusinessException("部门编码不能为空");
        }
        
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getCode, code)
               .eq(SysDepartment::getDeleted, false);
        
        SysDepartment department = super.getOne(wrapper);
        return department != null ? departmentMap.toDto(department) : null;
    }

    @Override
    @Cacheable(value = USER_DEPARTMENT_CACHE, key = "#userId")
    public SysDepartmentDto getUserDepartment(Long userId) {
        if (userId == null) {
            throw new BusinessException("用户ID不能为空");
        }
        
        // 使用 LambdaQuery 查询用户所属部门
        Long departmentId = getUserDepartmentId(userId);
        return departmentId != null ? get(departmentId) : null;
    }

    @Override
    @Cacheable(value = DEPARTMENT_TREE_CACHE, key = "'tree:' + (#parentId != null ? #parentId : 'root')")
    public List<SysDepartmentDto> getDepartmentTree(Long parentId) {
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        
        if (parentId != null) {
            wrapper.eq(SysDepartment::getParentId, parentId);
        } else {
            // 查询根部门，parent_id为0
            wrapper.eq(SysDepartment::getParentId, 0L);
        }
        
        wrapper.eq(SysDepartment::getDeleted, false)
               .eq(SysDepartment::getStatus, 1)
               .orderByAsc(SysDepartment::getSort)
               .orderByAsc(SysDepartment::getCreateTime);
        
        List<SysDepartment> departments = super.list(wrapper);
        
        return departments.stream()
                .map(department -> {
                    SysDepartmentDto dto = departmentMap.toDto(department);
                    dto.setChildren(getDepartmentTree(department.getId()));
                    return dto;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<SysDepartmentDto> getChildDepartments(Long parentId) {
        if (parentId == null) {
            throw new BusinessException("父部门ID不能为空");
        }
        
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getParentId, parentId)
               .eq(SysDepartment::getDeleted, false)
               .orderByAsc(SysDepartment::getSort)
               .orderByAsc(SysDepartment::getCreateTime);
        
        List<SysDepartment> childDepartments = super.list(wrapper);
        return departmentMap.toDtoList(childDepartments);
    }

    @Override
    @Cacheable(value = DEPARTMENT_USERS_CACHE, key = "#departmentId + ':' + #includeSubDepartments")
    public List<Long> getDepartmentUsers(Long departmentId, boolean includeSubDepartments) {
        if (departmentId == null) {
            throw new BusinessException("部门ID不能为空");
        }
        
        if (!includeSubDepartments) {
            // 只查询当前部门的用户
            return getUserIdsByDepartmentIds(Collections.singletonList(departmentId));
        }
        
        // 递归收集所有子部门ID
        Set<Long> departmentIds = new HashSet<>();
        departmentIds.add(departmentId);
        collectSubDepartmentIds(departmentId, departmentIds);
        
        return getUserIdsByDepartmentIds(new ArrayList<>(departmentIds));
    }

    @Override
    public boolean existsByCode(String code, Long excludeId) {
        if (!StringUtils.hasText(code)) {
            return false;
        }
        
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getCode, code)
               .eq(SysDepartment::getDeleted, false);
        
        if (excludeId != null) {
            wrapper.ne(SysDepartment::getId, excludeId);
        }
        
        return super.count(wrapper) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {DEPARTMENT_CACHE, USER_DEPARTMENT_CACHE}, allEntries = true)
    public void enableDepartment(Long departmentId) {
        updateDepartmentStatus(departmentId, 1, "启用");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {DEPARTMENT_CACHE, USER_DEPARTMENT_CACHE}, allEntries = true)
    public void disableDepartment(Long departmentId) {
        updateDepartmentStatus(departmentId, 0, "禁用");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {DEPARTMENT_CACHE, DEPARTMENT_TREE_CACHE}, allEntries = true)
    public void moveDepartment(Long departmentId, Long targetParentId, Integer targetSort) {
        log.debug("移动部门，部门ID: {}, 目标父部门ID: {}, 目标排序: {}", departmentId, targetParentId, targetSort);
        
        if (departmentId == null) {
            throw new BusinessException("部门ID不能为空");
        }
        
        SysDepartment department = getByIdOrThrow(departmentId);
        
        // 检查是否移动到自己的子部门
        if (targetParentId != null && isDescendant(departmentId, targetParentId)) {
            throw new BusinessException("不能将部门移动到其子部门下");
        }
        
        department.setParentId(targetParentId != null ? targetParentId : 0L);
        if (targetSort != null) {
            department.setSort(targetSort);
        }
        
        // 重新构建祖先路径
        buildAncestors(department);
        
        if (!super.updateById(department)) {
            throw new BusinessException("部门移动失败");
        }
        
        log.info("部门移动成功，部门ID: {}, 目标父部门ID: {}", departmentId, targetParentId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDepartmentSorts(List<SysDepartmentDto> departmentSorts) {
        if (departmentSorts == null || departmentSorts.isEmpty()) {
            return;
        }
        
        List<SysDepartment> departments = departmentSorts.stream()
                .map(dto -> {
                    SysDepartment department = new SysDepartment();
                    department.setId(dto.getId());
                    department.setSort(dto.getSort());
                    return department;
                })
                .collect(Collectors.toList());
        
        if (!super.updateBatchById(departments)) {
            throw new BusinessException("批量更新部门排序失败");
        }
        
        log.info("批量更新部门排序成功，更新数量: {}", departments.size());
    }

    @Override
    public IPage<?> getDepartmentMembers(DepartmentQuery query) {
        // TODO: 实现部门成员分页查询
        throw new BusinessException("部门成员查询功能待实现");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDepartmentMember(DepartmentOperateDto request) {
        // TODO: 实现添加部门成员
        throw new BusinessException("添加部门成员功能待实现");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeDepartmentMember(DepartmentOperateDto request) {
        // TODO: 实现移除部门成员
        throw new BusinessException("移除部门成员功能待实现");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setDepartmentManager(DepartmentOperateDto request) {
        // TODO: 实现设置部门负责人
        throw new BusinessException("设置部门负责人功能待实现");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moveDepartment(DepartmentOperateDto request) {
        if (request == null || request.getDepartmentId() == null) {
            throw new BusinessException("移动请求参数不能为空");
        }
        
        moveDepartment(Long.valueOf(request.getDepartmentId()), 
                      request.getTargetParentId() != null ? Long.valueOf(request.getTargetParentId()) : null, 
                      request.getTargetSort());
    }

    @Override
    public List<SysUserDto> getDepartmentManagers() {
        log.debug("查询部门管理员用户列表");
        
        // 查询具有部门管理员角色的用户
        LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysRole::getCode, DEPT_ADMIN.getCode())
                   .eq(SysRole::getStatus, 1)
                   .eq(SysRole::getDeleted, false);
        
        SysRole deptManagerRole = sysRoleMapper.selectOne(roleWrapper);
        if (deptManagerRole == null) {
            return Collections.emptyList();
        }
        
        // 查询拥有该角色的用户
        LambdaQueryWrapper<SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
        userRoleWrapper.eq(SysUserRole::getRoleId, deptManagerRole.getId())
                       .eq(SysUserRole::getDeleted, false);
        
        List<SysUserRole> userRoles = sysUserRoleMapper.selectList(userRoleWrapper);
        if (userRoles.isEmpty()) {
            log.info("未找到具有部门管理员角色的用户");
            return Collections.emptyList();
        }
        
        // 获取用户ID列表
        List<Long> userIds = userRoles.stream()
                .map(SysUserRole::getUserId)
                .collect(Collectors.toList());
        
        // 查询用户详情
        LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.in(SysUser::getId, userIds)
                   .eq(SysUser::getStatus, 1)
                   .eq(SysUser::getDeleted, false)
                   .orderByAsc(SysUser::getRealName);
        
        List<SysUser> users = userMapper.selectList(userWrapper);
        
        // 转换为DTO
        return users.stream()
                .map(SysUserMap.INSTANCE::toDto)
                .collect(Collectors.toList());
    }

    // ========== 私有辅助方法 ==========

    /**
     * 检查目标部门是否为源部门的后代
     */
    private boolean isDescendant(Long ancestorId, Long descendantId) {
        if (ancestorId == null || descendantId == null || ancestorId.equals(descendantId)) {
            return false;
        }
        
        SysDepartment descendant = super.getById(descendantId);
        if (descendant == null || descendant.getAncestors() == null) {
            return false;
        }
        
        return descendant.getAncestors().contains(ancestorId.toString());
    }

    private void validateDepartmentDto(SysDepartmentDto dto) {
        if (dto == null) {
            throw new BusinessException("部门信息不能为空");
        }
        if (!StringUtils.hasText(dto.getName())) {
            throw new BusinessException("部门名称不能为空");
        }
        if (!StringUtils.hasText(dto.getCode())) {
            throw new BusinessException("部门编码不能为空");
        }
    }

    private void setDefaultValues(SysDepartment department) {
        if (department.getStatus() == null) {
            department.setStatus(1);
        }
        if (department.getSort() == null) {
            department.setSort(0);
        }
    }

    private void buildAncestors(SysDepartment department) {
        if (department.getParentId() != null && department.getParentId() > 0) {
            SysDepartment parentDepartment = super.getById(department.getParentId());
            if (parentDepartment == null) {
                throw new BusinessException("父部门不存在，ID: " + department.getParentId());
            }
            
            String ancestors = parentDepartment.getAncestors() != null ? 
                parentDepartment.getAncestors() + "," + department.getParentId() : 
                String.valueOf(department.getParentId());
            department.setAncestors(ancestors);
        } else {
            department.setParentId(0L);
            department.setAncestors("0");
        }
    }

    private SysDepartment getByIdOrThrow(Serializable id) {
        SysDepartment department = super.getById(id);
        if (department == null) {
            throw new BusinessException("部门不存在，ID: " + id);
        }
        return department;
    }

    private void updateDepartmentStatus(Long departmentId, Integer status, String operation) {
        SysDepartment department = getByIdOrThrow(departmentId);
        department.setStatus(status);
        
        if (!super.updateById(department)) {
            throw new BusinessException("部门" + operation + "失败");
        }
        
        log.info("部门{}成功，部门ID: {}", operation, departmentId);
    }

    private void collectSubDepartmentIds(Long parentId, Set<Long> departmentIds) {
        List<SysDepartmentDto> childDepartments = getChildDepartments(parentId);
        for (SysDepartmentDto child : childDepartments) {
            departmentIds.add(child.getId());
            collectSubDepartmentIds(child.getId(), departmentIds);
        }
    }

    private SysDepartmentDto convertToDto(SysDepartment department) {
        return departmentMap.toDto(department);
    }

    // ========== 自定义查询方法（使用 LambdaQuery 实现） ==========

    /**
     * 根据用户ID获取用户所属部门ID
     * 
     * @param userId 用户ID
     * @return 部门ID
     */
    private Long getUserDepartmentId(Long userId) {
        // 方式1：通过用户表的 departmentId 字段查询
        SysUser user = userMapper.selectOne(
            new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getDepartmentId)
                .eq(SysUser::getId, userId)
        );
        
        if (user != null && user.getDepartmentId() != null) {
            return user.getDepartmentId();
        }
        
        // 方式2：通过部门用户关联表查询
        SysDepartmentUser departmentUser = departmentUserMapper.selectOne(
            new LambdaQueryWrapper<SysDepartmentUser>()
                .select(SysDepartmentUser::getDepartmentId)
                .eq(SysDepartmentUser::getUserId, userId)
                .last("LIMIT 1")
        );
        
        return departmentUser != null ? departmentUser.getDepartmentId() : null;
    }

    /**
     * 根据部门ID列表获取用户ID列表
     * 
     * @param departmentIds 部门ID列表
     * @return 用户ID列表
     */
    private List<Long> getUserIdsByDepartmentIds(List<Long> departmentIds) {
        if (departmentIds == null || departmentIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 方式1：通过用户表的 departmentId 字段查询
        List<SysUser> users = userMapper.selectList(
            new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId)
                .in(SysUser::getDepartmentId, departmentIds)
                .eq(SysUser::getStatus, 1) // 只查询启用的用户
        );
        
        Set<Long> userIds = users.stream()
            .map(SysUser::getId)
            .collect(Collectors.toSet());
        
        // 方式2：通过部门用户关联表查询（补充查询）
        List<SysDepartmentUser> departmentUsers = departmentUserMapper.selectList(
            new LambdaQueryWrapper<SysDepartmentUser>()
                .select(SysDepartmentUser::getUserId)
                .in(SysDepartmentUser::getDepartmentId, departmentIds)
        );
        
        departmentUsers.stream()
            .map(SysDepartmentUser::getUserId)
            .forEach(userIds::add);
        
        return new ArrayList<>(userIds);
    }
}